package com.dingding.gmall.ware.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dingding.gmall.common.dto.mq.order.OrderInfoDTO;
import com.dingding.gmall.common.dto.mq.ware.StockDetailDTO;
import com.dingding.gmall.common.dto.mq.ware.StockLockedSuccessDTO;
import com.dingding.gmall.common.exception.NoStockException;
import com.dingding.gmall.common.utils.PageUtils;
import com.dingding.gmall.common.utils.Query;
import com.dingding.gmall.ware.dao.WareSkuDao;
import com.dingding.gmall.ware.dto.OrderEntityDTO;
import com.dingding.gmall.ware.dto.OrderItemDTO;
import com.dingding.gmall.ware.dto.WareSkuLockDTO;
import com.dingding.gmall.ware.entity.WareOrderTaskDetailEntity;
import com.dingding.gmall.ware.entity.WareOrderTaskEntity;
import com.dingding.gmall.ware.entity.WareSkuEntity;
import com.dingding.gmall.ware.feign.OrderFeignService;
import com.dingding.gmall.ware.service.WareOrderTaskDetailService;
import com.dingding.gmall.ware.service.WareOrderTaskService;
import com.dingding.gmall.ware.service.WareSkuService;
import com.dingding.gmall.ware.vo.SkuHasStockVO;
import com.google.common.collect.Lists;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("wareSkuService")
@Slf4j
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    private WareSkuDao wareSkuDao;

    @Autowired
    private WareOrderTaskService wareOrderTaskService;

    @Autowired
    private WareOrderTaskDetailService wareOrderTaskDetailService;

    @Autowired
    private OrderFeignService orderFeignService;

    @Autowired
    private RabbitTemplate rabbitTemplate;



    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        String skuId = (String) params.get("skuId");
        if (StringUtils.isNotBlank(skuId)) {
            wrapper.eq("sku_id",skuId);
        }
        String wareId = (String) params.get("wareId");
        if (StringUtils.isNotBlank(skuId)) {
            wrapper.eq("ware_id",wareId);
        }
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }

    @Override
    public List<SkuHasStockVO> getSkusHasStock(List<Long> skuIds) {
        List<SkuHasStockVO> list = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(skuIds)){
            for (Long skuId : skuIds) {
                SkuHasStockVO skuHasStockVO = new SkuHasStockVO();
                //查询当前sku的总库存量
                //sum(stock-stock_locked) 库存总量 - 库存锁定量
                Long count = baseMapper.getSkuStock(skuId);
                skuHasStockVO.setSkuId(skuId);
                Boolean result = count != null && count > 0;
                skuHasStockVO.setHasStock(result);
                list.add(skuHasStockVO);
            }
        }
        return list;
    }

    @Override
    @Transactional(rollbackFor = NoStockException.class)
    public boolean orderLockStock(WareSkuLockDTO wareSkuLockDTO) {
        //保存库存工作单详情
        WareOrderTaskEntity taskEntity = new WareOrderTaskEntity();
        taskEntity.setOrderSn(wareSkuLockDTO.getOrderSn());
        wareOrderTaskService.save(taskEntity);

        List<OrderItemDTO> lockSkuInfo = wareSkuLockDTO.getLockSkuInfo();
        if (CollectionUtils.isNotEmpty(lockSkuInfo)) {
            List<Long> skuIds = lockSkuInfo.stream().map(OrderItemDTO::getSkuId).collect(Collectors.toList());
            QueryWrapper<WareSkuEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("sku_id", skuIds);
            List<WareSkuEntity> wareSkuEntities = this.list(queryWrapper);
            List<SkuWareHasStock> skuWareHasStockList = null;
            if (CollectionUtils.isNotEmpty(wareSkuEntities)) {
                Map<Long, List<Long>> collect = wareSkuEntities.stream().collect(Collectors.groupingBy(WareSkuEntity::getSkuId,
                        Collectors.mapping(WareSkuEntity::getWareId, Collectors.toList())));
                skuWareHasStockList = lockSkuInfo.stream().map(item -> {
                    SkuWareHasStock skuWareHasStock = new SkuWareHasStock();
                    Long skuId = item.getSkuId();
                    Integer number = item.getItemCount();
                    List<Long> wardIds = collect.get(skuId);
                    skuWareHasStock.setSkuId(skuId);
                    skuWareHasStock.setWareIds(wardIds);
                    skuWareHasStock.setNumber(number);
                    return skuWareHasStock;
                }).collect(Collectors.toList());
            }
            if (CollectionUtils.isNotEmpty(skuWareHasStockList)) {
                for (SkuWareHasStock stock : skuWareHasStockList) {
                    boolean skuLock = false;
                    List<Long> wareIds = stock.getWareIds();
                    Long skuId = stock.getSkuId();
                    Integer number = stock.getNumber();
                    if (CollectionUtils.isEmpty(wareIds)) {
                        throw new NoStockException(stock.getSkuId());
                    }
                    //锁库存
                    for (Long wareId : wareIds) {
                        Long count = wareSkuDao.lockSkuStock(skuId, wareId, number);
                         if (count == 1) {
                            //锁成功
                            skuLock = true;
                            //MQ消息锁定成功
                             WareOrderTaskDetailEntity wareOrderTaskDetailEntity = new WareOrderTaskDetailEntity();
                             wareOrderTaskDetailEntity.setSkuId(skuId);
                             wareOrderTaskDetailEntity.setSkuNum(number);
                             wareOrderTaskDetailEntity.setTaskId(taskEntity.getId());
                             wareOrderTaskDetailEntity.setLockStatus(1);
                             wareOrderTaskDetailEntity.setWareId(wareId);
                             wareOrderTaskDetailService.save(wareOrderTaskDetailEntity);
                             StockLockedSuccessDTO dto = new StockLockedSuccessDTO();
                             dto.setId(taskEntity.getId());
                             StockDetailDTO stockDetailDTO = new StockDetailDTO();
                             BeanUtils.copyProperties(wareOrderTaskDetailEntity, stockDetailDTO);
                             dto.setStockDetailDTO(stockDetailDTO);
                             rabbitTemplate.convertAndSend("stock-event-exchange", "stock.locked", dto);
                             //跳出该仓库
                            break;
                        }
                         //重试下一个仓库
                    }
                    if (!skuLock) {
                        log.info("库存不足,skuId:{}", stock.getSkuId());
                        throw new NoStockException(stock.getSkuId());
                    }
                }
            }

        }
        return true;
    }



    private void releaseWare(Long skuId, Long wareId, Integer num, Long taskDetailId) {
        wareSkuDao.unlockStock(skuId, wareId, num);
        WareOrderTaskDetailEntity entity = new WareOrderTaskDetailEntity();
        entity.setId(taskDetailId);
        entity.setLockStatus(2);
        wareOrderTaskDetailService.updateById(entity);
    }

    /**
     * 仓库服务发过来的消息
     * 1,库存自动解锁
     * 2,订单保存失败
     * 3,锁库存失败
     */
    @Override
    public void unlockStock(StockLockedSuccessDTO dto) {
        //工作单id
        StockDetailDTO stockDetailDTO = dto.getStockDetailDTO();
        Long skuId = stockDetailDTO.getSkuId();
        Long detailId = stockDetailDTO.getId();
        Integer num = stockDetailDTO.getSkuNum();
        Long wareId = stockDetailDTO.getWareId();
        WareOrderTaskDetailEntity wareOrderTaskDetailEntity = wareOrderTaskDetailService.getById(detailId);
        if (wareOrderTaskDetailEntity != null) {
            //根据订单号查询订单状态
            WareOrderTaskEntity wareOrderTaskEntity = wareOrderTaskService.getById(wareOrderTaskDetailEntity.getTaskId());
            if (wareOrderTaskEntity != null) {
                String orderSn = wareOrderTaskEntity.getOrderSn();
                OrderEntityDTO orderEntityDTO = orderFeignService.getOrderStatus(orderSn);
                if (orderEntityDTO == null || orderEntityDTO.getStatus() == 4) {
                    //说明订单已被取消或订单不存在都要解锁库存
                    if (wareOrderTaskDetailEntity.getLockStatus() == 1){
                        //锁定状态才能解锁库存
                        releaseWare(skuId, wareId, num, detailId);
                    }
                } else {
                    return;
                }
            } else {
                throw new RuntimeException("RPC调用失败");
            }
        }
    }

    /**
     * 订单服务发过来的消息
     * @param dto
     */
    @Override
    @Transactional
    public void unlockStock(OrderInfoDTO dto) {
        //查一下最新的解锁库存
        String orderSn = dto.getOrderSn();
        WareOrderTaskEntity wareOrderTaskEntity = wareOrderTaskService.getOrderTaskByOrderSn(orderSn);
        if (wareOrderTaskEntity != null) {
            Long taskId = wareOrderTaskEntity.getId();
            List<WareOrderTaskDetailEntity> list = wareOrderTaskDetailService.getUnlockedOrderTaskDeatilList(taskId);
            if (CollectionUtils.isNotEmpty(list)) {
                for (WareOrderTaskDetailEntity entity : list) {
                    Long skuId = entity.getSkuId();
                    Long wareId = entity.getWareId();
                    Integer num = entity.getSkuNum();
                    Long id = entity.getId();
                    releaseWare(skuId, wareId, num, id);
                }
            }
        }
    }

    @Data
    class SkuWareHasStock{
        private Long skuId;
        private Integer number;
        private List<Long> wareIds;
    }
}